const Redis = require('ioredis');
const config = require('./config');
const logger = require('./logger');

// Redis配置选项
const redisOptions = {
  host: config.redis.host,
  port: config.redis.port,
  password: config.redis.password,
  db: config.redis.db,
  keyPrefix: config.redis.keyPrefix,
  retryDelayOnFailover: config.redis.retryDelayOnFailover,
  enableReadyCheck: config.redis.enableReadyCheck,
  maxRetriesPerRequest: config.redis.maxRetriesPerRequest,
  lazyConnect: config.redis.lazyConnect,
  connectTimeout: config.redis.connectTimeout,
  commandTimeout: config.redis.commandTimeout,
  
  // 重试策略
  retryStrategy: (times) => {
    const delay = Math.min(times * 50, 2000);
    logger.warn(`Redis连接重试 ${times} 次，延迟 ${delay}ms`);
    return delay;
  },
  
  // 重连策略
  reconnectOnError: (err) => {
    const targetError = 'READONLY';
    return err.message.includes(targetError);
  },
  
  // 连接名称
  connectionName: `${config.app.name}-${config.env}-${process.pid}`,
  
  // 家族优先级
  family: 4,
  
  // 保持连接活跃
  keepAlive: 30000,
  
  // 启用离线队列
  enableOfflineQueue: true
};

// 创建Redis客户端
const redis = new Redis(redisOptions);

// 连接事件监听
redis.on('connect', () => {
  logger.info('Redis连接已建立');
});

redis.on('ready', () => {
  logger.info('Redis连接就绪');
});

redis.on('error', (err) => {
  logger.error('Redis连接错误:', err);
});

redis.on('close', () => {
  logger.warn('Redis连接已关闭');
});

redis.on('reconnecting', (ms) => {
  logger.info(`Redis正在重连，延迟 ${ms}ms`);
});

redis.on('end', () => {
  logger.warn('Redis连接已结束');
});

// Redis工具函数
const RedisUtils = {
  // 设置键值对
  async set(key, value, ttl = null) {
    try {
      const serializedValue = JSON.stringify(value);
      
      if (ttl) {
        await redis.setex(key, ttl, serializedValue);
      } else {
        await redis.set(key, serializedValue);
      }
      
      logger.debug(`Redis SET: ${key}`, { ttl });
      return true;
    } catch (error) {
      logger.error(`Redis SET失败: ${key}`, error);
      throw error;
    }
  },
  
  // 获取值
  async get(key) {
    try {
      const value = await redis.get(key);
      
      if (value === null) {
        logger.debug(`Redis GET: ${key} - 未找到`);
        return null;
      }
      
      const parsedValue = JSON.parse(value);
      logger.debug(`Redis GET: ${key} - 成功`);
      
      return parsedValue;
    } catch (error) {
      logger.error(`Redis GET失败: ${key}`, error);
      throw error;
    }
  },
  
  // 删除键
  async del(key) {
    try {
      const result = await redis.del(key);
      logger.debug(`Redis DEL: ${key} - ${result ? '成功' : '键不存在'}`);
      return result;
    } catch (error) {
      logger.error(`Redis DEL失败: ${key}`, error);
      throw error;
    }
  },
  
  // 检查键是否存在
  async exists(key) {
    try {
      const result = await redis.exists(key);
      logger.debug(`Redis EXISTS: ${key} - ${result ? '存在' : '不存在'}`);
      return result === 1;
    } catch (error) {
      logger.error(`Redis EXISTS失败: ${key}`, error);
      throw error;
    }
  },
  
  // 设置过期时间
  async expire(key, ttl) {
    try {
      const result = await redis.expire(key, ttl);
      logger.debug(`Redis EXPIRE: ${key} - ${ttl}s`);
      return result === 1;
    } catch (error) {
      logger.error(`Redis EXPIRE失败: ${key}`, error);
      throw error;
    }
  },
  
  // 获取剩余过期时间
  async ttl(key) {
    try {
      const result = await redis.ttl(key);
      logger.debug(`Redis TTL: ${key} - ${result}s`);
      return result;
    } catch (error) {
      logger.error(`Redis TTL失败: ${key}`, error);
      throw error;
    }
  },
  
  // 原子递增
  async incr(key, step = 1) {
    try {
      const result = await redis.incrby(key, step);
      logger.debug(`Redis INCR: ${key} + ${step} = ${result}`);
      return result;
    } catch (error) {
      logger.error(`Redis INCR失败: ${key}`, error);
      throw error;
    }
  },
  
  // 原子递减
  async decr(key, step = 1) {
    try {
      const result = await redis.decrby(key, step);
      logger.debug(`Redis DECR: ${key} - ${step} = ${result}`);
      return result;
    } catch (error) {
      logger.error(`Redis DECR失败: ${key}`, error);
      throw error;
    }
  },
  
  // 哈希操作
  hash: {
    async set(key, field, value) {
      try {
        const serializedValue = JSON.stringify(value);
        const result = await redis.hset(key, field, serializedValue);
        logger.debug(`Redis HSET: ${key}.${field}`);
        return result;
      } catch (error) {
        logger.error(`Redis HSET失败: ${key}.${field}`, error);
        throw error;
      }
    },
    
    async get(key, field) {
      try {
        const value = await redis.hget(key, field);
        
        if (value === null) {
          logger.debug(`Redis HGET: ${key}.${field} - 未找到`);
          return null;
        }
        
        const parsedValue = JSON.parse(value);
        logger.debug(`Redis HGET: ${key}.${field} - 成功`);
        
        return parsedValue;
      } catch (error) {
        logger.error(`Redis HGET失败: ${key}.${field}`, error);
        throw error;
      }
    },
    
    async del(key, field) {
      try {
        const result = await redis.hdel(key, field);
        logger.debug(`Redis HDEL: ${key}.${field}`);
        return result;
      } catch (error) {
        logger.error(`Redis HDEL失败: ${key}.${field}`, error);
        throw error;
      }
    },
    
    async getAll(key) {
      try {
        const hash = await redis.hgetall(key);
        const result = {};
        
        for (const [field, value] of Object.entries(hash)) {
          result[field] = JSON.parse(value);
        }
        
        logger.debug(`Redis HGETALL: ${key} - ${Object.keys(result).length} 个字段`);
        
        return result;
      } catch (error) {
        logger.error(`Redis HGETALL失败: ${key}`, error);
        throw error;
      }
    }
  },
  
  // 列表操作
  list: {
    async push(key, ...values) {
      try {
        const serializedValues = values.map(v => JSON.stringify(v));
        const result = await redis.lpush(key, ...serializedValues);
        logger.debug(`Redis LPUSH: ${key} - ${values.length} 个元素`);
        return result;
      } catch (error) {
        logger.error(`Redis LPUSH失败: ${key}`, error);
        throw error;
      }
    },
    
    async pop(key) {
      try {
        const value = await redis.rpop(key);
        
        if (value === null) {
          logger.debug(`Redis RPOP: ${key} - 列表为空`);
          return null;
        }
        
        const parsedValue = JSON.parse(value);
        logger.debug(`Redis RPOP: ${key} - 成功`);
        
        return parsedValue;
      } catch (error) {
        logger.error(`Redis RPOP失败: ${key}`, error);
        throw error;
      }
    },
    
    async length(key) {
      try {
        const result = await redis.llen(key);
        logger.debug(`Redis LLEN: ${key} - ${result}`);
        return result;
      } catch (error) {
        logger.error(`Redis LLEN失败: ${key}`, error);
        throw error;
      }
    },
    
    async range(key, start = 0, stop = -1) {
      try {
        const values = await redis.lrange(key, start, stop);
        const result = values.map(v => JSON.parse(v));
        logger.debug(`Redis LRANGE: ${key} [${start}:${stop}] - ${result.length} 个元素`);
        return result;
      } catch (error) {
        logger.error(`Redis LRANGE失败: ${key}`, error);
        throw error;
      }
    }
  },
  
  // 集合操作
  set: {
    async add(key, ...members) {
      try {
        const serializedMembers = members.map(m => JSON.stringify(m));
        const result = await redis.sadd(key, ...serializedMembers);
        logger.debug(`Redis SADD: ${key} - ${members.length} 个成员`);
        return result;
      } catch (error) {
        logger.error(`Redis SADD失败: ${key}`, error);
        throw error;
      }
    },
    
    async remove(key, ...members) {
      try {
        const serializedMembers = members.map(m => JSON.stringify(m));
        const result = await redis.srem(key, ...serializedMembers);
        logger.debug(`Redis SREM: ${key} - ${members.length} 个成员`);
        return result;
      } catch (error) {
        logger.error(`Redis SREM失败: ${key}`, error);
        throw error;
      }
    },
    
    async members(key) {
      try {
        const values = await redis.smembers(key);
        const result = values.map(v => JSON.parse(v));
        logger.debug(`Redis SMEMBERS: ${key} - ${result.length} 个成员`);
        return result;
      } catch (error) {
        logger.error(`Redis SMEMBERS失败: ${key}`, error);
        throw error;
      }
    },
    
    async isMember(key, member) {
      try {
        const serializedMember = JSON.stringify(member);
        const result = await redis.sismember(key, serializedMember);
        logger.debug(`Redis SISMEMBER: ${key} - ${result ? '是成员' : '不是成员'}`);
        return result === 1;
      } catch (error) {
        logger.error(`Redis SISMEMBER失败: ${key}`, error);
        throw error;
      }
    }
  },
  
  // 模式匹配删除
  async deletePattern(pattern) {
    try {
      const keys = await redis.keys(pattern);
      
      if (keys.length === 0) {
        logger.debug(`Redis DELETE PATTERN: ${pattern} - 未找到匹配的键`);
        return 0;
      }
      
      const result = await redis.del(...keys);
      logger.debug(`Redis DELETE PATTERN: ${pattern} - 删除了 ${result} 个键`);
      
      return result;
    } catch (error) {
      logger.error(`Redis DELETE PATTERN失败: ${pattern}`, error);
      throw error;
    }
  },
  
  // 获取Redis信息
  async getInfo() {
    try {
      const info = await redis.info();
      const memory = await redis.info('memory');
      const stats = await redis.info('stats');
      
      return {
        info,
        memory,
        stats,
        timestamp: new Date().toISOString()
      };
    } catch (error) {
      logger.error('获取Redis信息失败:', error);
      throw error;
    }
  },
  
  // 检查健康状态
  async checkHealth() {
    try {
      const startTime = Date.now();
      
      await redis.ping();
      
      const responseTime = Date.now() - startTime;
      
      return {
        status: 'healthy',
        responseTime: `${responseTime}ms`,
        timestamp: new Date().toISOString()
      };
    } catch (error) {
      return {
        status: 'unhealthy',
        error: error.message,
        timestamp: new Date().toISOString()
      };
    }
  }
};

// 优雅关闭
const closeConnection = async () => {
  try {
    await redis.quit();
    logger.info('Redis连接已关闭');
  } catch (error) {
    logger.error('关闭Redis连接时出错:', error);
    redis.disconnect();
  }
};

// 导出
module.exports = redis;
module.exports.utils = RedisUtils;
module.exports.close = closeConnection;